from server import db, app_auth, user_opt
from flask import jsonify, Blueprint, request, g, make_response
from server.model.app_user import AppUser
from server.model import set_field
import requests
import emoji
import re
from os import getenv

a_app_user = Blueprint('app/app_user', __name__)
exclude_data = {'open_id', 'session_key', 'password', 'phone'}


@app_auth.verify_token
def verify_token(token):
    if not token:
        return False

    user = AppUser.verify_auth_token(token)
    if not user:
        return False
    g.user = user
    g.user.user_type = 'app_user'
    return True


@app_auth.error_handler
def unauthorized():
    return make_response(jsonify({
        'code': 40001,
        'message': "Unauthorized access"
    }), 401)


@a_app_user.route('/login', methods=['GET'])
def user_login():
    """
        @@@
        #### Args:
                code = request.args.get('code')
        #### Returns::
                {
                    'code': 200,
                    'user_id': g.user.id,
                    'nick_name': g.user.nick_name,
                    "token": token.decode(),
                }
                {
                    'code': 500,
                    'msg': "code失效或不正确"
                }
    """
    code = request.args.get('code')
    print("doing login..", code)

    try:
        params = {
            'appid': getenv('WECHAT_APPID'),
            'secret': getenv('WECHAT_SECRET'),
            'js_code': code,
            'grant_type': 'authorization_code'
        }
        wx_login_api = 'https://api.weixin.qq.com/sns/jscode2session'
        resp = requests.get(wx_login_api, params=params)
        data = resp.json()
        print("got login info :", data)
        if 'errcode' in data:
            return {
                'code': 500,
                'msg': "授权失败, 错误信息:%s " % data['errmsg']
            }
        openid = data['openid']
        session_key = data['session_key']
        print("---session:", session_key)
        if openid and session_key:
            user_info = AppUser.query.filter(AppUser.open_id == openid).first()

            if user_info is None:
                user_info = AppUser(open_id=openid)
                db.session.add(user_info)
            user_info.session_key = session_key
            db.session.commit()
            g.user = user_info
            token = user_info.generate_auth_token()
            return jsonify({
                'code': 20000,
                'user_id': g.user.id,
                'nick_name': g.user.nick_name,
                "token": "Bearer %s" % token.decode(),
            })
        return jsonify({
            'code': 50001,
            'msg': "code失效或不正确"
        })
    except Exception as e:
        print("user login error", e)
        return jsonify({
            'code': 50002,
            'msg': "未知错误"
        })


@a_app_user.route('/upload_info', methods=['POST'])
@app_auth.login_required
def upload_user_info():
    """
        @@@
        #### Args:
                user_info = request.json['user_info']
        #### Returns::
                {'code': 200, 'msg': 'ok'}
    """
    user_info = request.json['user_info']
    print("upload_info--", user_info)
    name = emoji.demojize(user_info['nickName'])
    name = re.sub(r':(.+?):', '', name).strip()
    print("got name:", name)
    g.user.nick_name = name
    g.user.head_url = user_info['avatarUrl']
    db.session.commit()
    return jsonify({'code': 20000, 'msg': 'ok'})


@a_app_user.route('/upload_phone', methods=['POST'])
@app_auth.login_required
def upload_phone():
    """
        @@@
        #### Args:
                encryptedData
                iv
        #### Returns::
                {'code': 200, 'msg': 'ok'}
    """
    import base64
    from Crypto.Cipher import AES
    import json
    app_user = g.user
    args = request.json
    encrypted_data = args.get('encryptedData')
    iv = args.get('iv')
    app_id = getenv('WECHAT_APPID')
    session_key = app_user.session_key
    print(">>>>>", args, app_id, session_key)
    try:
        def unpad(s):
            return s[:-ord(s[len(s) - 1:])]

        # base64 decode
        session_key = base64.b64decode(session_key)
        encrypted_data = base64.b64decode(encrypted_data)
        iv = base64.b64decode(iv)
        cipher = AES.new(session_key, AES.MODE_CBC, iv)
        unpack_result = unpad(cipher.decrypt(encrypted_data))
        print(">>>>>", type(unpack_result))
        try:
            decrypted = json.loads(unpack_result)
            if decrypted['watermark']['appid'] != app_id:
                print('Invalid Buffer')
        except Exception as e:
            print("not a json format")
            return jsonify({'code': 50002, 'msg': '获取手机号失败,请联系管理员'})

        phone_num = decrypted.get('phoneNumber')
        if not phone_num:
            return jsonify({'code': 50002, 'msg': '获取手机号失败,请联系管理员'})

        print("got the phone:", app_user.phone, bool(app_user.phone))
        app_user.phone = phone_num
        db.session.commit()

        return jsonify({'code': 20000, 'phone': phone_num})
    except Exception as e:
        db.session.rollback()
        print("get app user phone error", e)

    return jsonify({'code': 50001, 'message': "获取手机号失败时发生错误"})


@a_app_user.route('/<int:pid>', methods=['PUT'])
@app_auth.login_required
def edit_app_user(pid):
    """
    @@@
    #### Args:
           app_user/id
    #### Returns::
            {'code': 20000, 'message': "app用户修改成功"}
            {'code': 50001, 'message': "修改app用户时发生错误"}
    """
    args = request.get_json()
    try:
        app_user = AppUser.query.filter_by(id=pid).first()
        set_field(app_user, args)

        db.session.commit()

        user_opt.send({
            "operation": "修改app用户",
            "method": "app用户管理",
            "params": pid,
            "user_id": g.user.id,
            "username": g.user.username
        })

        return jsonify({'code': 20000, 'message': "app用户修改成功"})
    except Exception as e:
        db.session.rollback()
        print("edit app_user error:", e)

    return jsonify({'code': 50001, 'message': "修改app用户时发生错误"})


@a_app_user.route('', methods=['GET'])
@app_auth.login_required
def get_detail():
    return jsonify({
        'code': 20000,
        'message': 'success',
        'info': g.user.to_dict(exclude=exclude_data),
    })

# >>>>> auto generate end <<<<<
